#include "Bootloader.h"
#include "../McuDrivers/flash/DataRecord.h"
#include "../McuDrivers/uart/uart.h"

uint8_t m_IsErased = 0;

//擦除中断向量表以及用户软件块
//Bootloader所在地址为： ORIGIN = 0x800, LENGTH = 0x6400
//  reset : ORIGIN = 0x0, LENGTH = 0x4
//  ivt   : ORIGIN = 0x4, LENGTH = 0x1FC
//  User  ：ORIGIN = 0x8000, LENGTH = 0x22FEC
// 每次擦除0x400个指令字，实际占用地址为0x800，例如擦除0x0,实际会擦除到0x7ff
// 配置寄存器不需要擦除，可以直接编程
void UserFlash_EraseIvtAndUserAppBlock()
{
    //擦除0x0000~0x07FE,reset and ivt
    EraseLargePage(0);  //擦除0x000000-0x00000800，0x008000-0x00FFFF
    EraseLargePage(1);  //擦除0x010000-0x01FFFE
    EraseLargePage(2);  //擦除0x020000-0x02F7FE
    
    //配置字 0x2AFF0~0x2AFFA，处于页0x02A800-0x02AFFE
    //由于配置字在最后一页，不能擦除最后一页
   
}

FlashAddr_t m_LastAddr={.Uint32Addr=0x000002,}; //要写入的首地址，默认为2，即第一次判断认为上一次是第二个，非第一个，不用填充上一个，防止第一次误判
OneInstruction_t dataForWrite[2]; //存储要写入的2个指令字，每个指令字2个16位组成

//解析Hex文件
//0、1表示开头
//2表示类型
//3、4、5表示地址，高字节在前，最高字节无
//6、7、8、9表示数据，低字节在前
void UserFlash_DataParseAddrData(uint8_t *data, uint8_t length)
{
    FlashAddr_t addr;
    OneInstruction_t dataTmp;
    
    addr.Uint16Addr.HighAddr = data[3];
    addr.Uint16Addr.LowAddr = data[4]*256 + data[5];
    
    dataTmp.HighLowUINT16s.LowWord = data[6]+data[7]*256;
    dataTmp.HighLowUINT16s.HighWord = data[8] + data[9]*256;
   
    if(addr.Uint32Addr==0x00000000)
        dataTmp.UINT32 = 0x00040800; //发送过来的跳转指令不接受，默认总跳转到bootloader首地址
    
    if(addr.Uint16Addr.LowAddr%4==0) //本次地址是组内第一个数据
    {
        if(m_LastAddr.Uint16Addr.LowAddr%4==0) //上一次也是第一个，则先填充上一次第二个指令字，写入flash，然后本次重新开始
        {
            dataForWrite[1].UINT32 = 0xffffff; //上一组第二个指令字填充
            InnerFlash_WriteInstructionsToFlash(m_LastAddr,dataForWrite,2); //上一次数据组合后，写入2指令字
        }
        //上一次是第1个或者第2个，本次都要重新开始
        dataForWrite[0].UINT32 = dataTmp.UINT32; //本次为第一个指令字
        
    }
    else //本次地址是第二个
    {
        if(m_LastAddr.Uint16Addr.LowAddr%4==0) //上一次是第一个，要继续判断是否连续
        {
            if((addr.Uint32Addr-m_LastAddr.Uint32Addr)==2) //与上一次连续，填充到上一次的数据中，并写入2个指令字
            {
                dataForWrite[1].UINT32 = dataTmp.UINT32; //本次为第二个指令字
                InnerFlash_WriteInstructionsToFlash(addr,dataForWrite,2); //本次次数据组合后，写入2指令字
            }
            else //与上一次不连续，填充上一次的第二个指令字，然后填充本次的第一个指令字，同时两次共写入4个指令字
            {
                dataForWrite[1].UINT32 = 0xffffff; //上组第二个指令字填充
                InnerFlash_WriteInstructionsToFlash(m_LastAddr,dataForWrite,2); //上一次数据组合后，写入2指令字
                
                dataForWrite[0].UINT32 = 0xffffff; //填充本组第一个指令字
                dataForWrite[1].UINT32 = dataTmp.UINT32; //本组第二个指令字
                InnerFlash_WriteInstructionsToFlash(addr,dataForWrite,2); //本次次数据组合后，写入2指令字
            }
        }
        else//上一次也是第2个，将本次第一个指令字也填充，写入
        {
                dataForWrite[0].UINT32 = 0xffffff; //填充本组第一个指令字
                dataForWrite[1].UINT32 = dataTmp.UINT32; //本组第二个指令字
                FlashAddr_t addrTmp;
                addrTmp.Uint32Addr = addr.Uint32Addr-2; //键入地址要为本组第一个地址
                InnerFlash_WriteInstructionsToFlash(addrTmp,dataForWrite,2); //本次次数据组合后，写入2指令字，注意地址要减2
        }
    }
    
    //赋予本次地址
    m_LastAddr.Uint32Addr = addr.Uint32Addr;
    
    //为防止出现奇指令，所以
   

    //写入Flash，每4个一组，占2个指令字，第一个指令字-低字节、高字节，第二个指令字-低字节、高字节
    //Length必须为4的倍数数，双指令字写入模式
    //例如 data[4]={0xaa05,0x0011,0xaa06,0x0022};，存入0x004000，即0x004000存入0x11aa05,0x004002存入0x22aa06
    //InnerFlash_WriteTwoWordsFlash(addrHighLow,,m_DataTmp,8);
    
}

/********************************************************
 * 已弃用
 ******************************************************
//行数
uint16_t m_LineNum=-1;

//线性地址，与页地址一致
uint16_t m_LineOffset = 0;

//拼接一行数据的起始索引
uint16_t m_LastIndex = 0;

//一行数据长度
uint8_t m_OneLineLength=0;

//一行数据
uint8_t m_OneLineData[100];

//解析Hex文件
//0、1表示开头
//2表示类型
//3、4表示行号表示行号，高字节在前
//5表示数据长度
//6、7、8、9表示数据
void UserFlash_DataParseRowSplit(uint8_t *data, uint8_t length)
{
    uint16_t line = (data[3]<<8)+data[4];
    uint8_t dataLength = data[5];
    uint8_t realDataLength = 0;
    uint8_t i;
    
    //同一行，拼接数据
    if(line!=m_LineNum)//不同行，重新开始
    {
        //元素复位
        m_LineNum=line;
        m_LastIndex=0;
    }
    
    //数据长度超过0xA0，表示该行数据结束
    realDataLength=dataLength>=0xA0?dataLength-0xA0:dataLength;
        
    //拼接行
    for(i=0;i<realDataLength;i++)
    {
        m_OneLineData[m_LastIndex+i] = data[6+i];
    }
    
    m_LastIndex+=realDataLength;
    
    //一行结束，回馈
    if(dataLength>0xA0)
    {
        Uart_WriteBytes_g(m_Bootloader_Send_StartFlag,2);
        Uart_WriteByte_g(0x02);
        Uart_WriteBytes_g(m_OneLineData,m_LastIndex);
        Uart_WriteBytes_g(m_Bootloader_Send_EndFlag,2);
        m_LastIndex=0;
    }
    
}
********************************************************/
